package com.coai.user.service

import com.coai.common.exception.ConflictException
import com.coai.common.exception.ResourceNotFoundException
import com.coai.common.exception.UnauthorizedException
import com.coai.common.exception.ValidationException
import com.coai.user.dto.*
import com.coai.user.model.User
import com.coai.user.model.UserStatus
import com.coai.user.repository.UserRepository
import com.coai.user.security.JwtTokenProvider
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDateTime

@Service
class UserService(
    private val userRepository: UserRepository,
    private val passwordEncoder: PasswordEncoder,
    private val jwtTokenProvider: JwtTokenProvider
) {
    
    @Transactional
    fun register(request: RegisterRequest): UserDto {
        // 检查用户名是否已存在
        if (userRepository.existsByUsername(request.username)) {
            throw ConflictException("用户名已存在")
        }
        
        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(request.email)) {
            throw ConflictException("邮箱已被注册")
        }
        
        val user = User(
            username = request.username,
            email = request.email,
            passwordHash = passwordEncoder.encode(request.password),
            displayName = request.displayName ?: request.username
        )
        
        val savedUser = userRepository.save(user)
        return savedUser.toDto()
    }
    
    @Transactional
    fun login(request: LoginRequest): LoginResponse {
        val user = userRepository.findByUsername(request.usernameOrEmail)
            .orElseGet {
                userRepository.findByEmail(request.usernameOrEmail)
                    .orElseThrow { UnauthorizedException("用户名或密码错误") }
            }
        
        if (!user.enabled) {
            throw UnauthorizedException("账户已被禁用")
        }
        
        if (!passwordEncoder.matches(request.password, user.passwordHash)) {
            throw UnauthorizedException("用户名或密码错误")
        }
        
        // 更新最后登录时间
        user.lastLoginAt = LocalDateTime.now()
        userRepository.save(user)
        
        // 生成JWT token
        val token = jwtTokenProvider.generateToken(user.id!!)
        val expiresIn = jwtTokenProvider.getExpirationTime()
        
        return LoginResponse(
            token = token,
            user = user.toDto(),
            expiresIn = expiresIn
        )
    }
    
    fun getUserById(userId: String): UserDto {
        val user = userRepository.findById(userId)
            .orElseThrow { ResourceNotFoundException("用户不存在") }
        return user.toDto()
    }
    
    fun getUserByUsername(username: String): UserDto {
        val user = userRepository.findByUsername(username)
            .orElseThrow { ResourceNotFoundException("用户不存在") }
        return user.toDto()
    }
    
    @Transactional
    fun updateUser(userId: String, request: UpdateUserRequest): UserDto {
        val user = userRepository.findById(userId)
            .orElseThrow { ResourceNotFoundException("用户不存在") }
        
        val updatedUser = user.copy(
            displayName = request.displayName ?: user.displayName,
            avatar = request.avatar ?: user.avatar,
            phone = request.phone ?: user.phone
        )
        
        val saved = userRepository.save(updatedUser)
        return saved.toDto()
    }
    
    @Transactional
    fun changePassword(userId: String, request: ChangePasswordRequest) {
        val user = userRepository.findById(userId)
            .orElseThrow { ResourceNotFoundException("用户不存在") }
        
        if (!passwordEncoder.matches(request.oldPassword, user.passwordHash)) {
            throw ValidationException("旧密码不正确")
        }
        
        val updatedUser = user.copy(
            passwordHash = passwordEncoder.encode(request.newPassword)
        )
        
        userRepository.save(updatedUser)
    }
    
    @Transactional
    fun updateStatus(userId: String, status: UserStatus) {
        userRepository.updateUserStatus(userId, status)
    }
    
    fun getActiveUsers(): List<UserDto> {
        return userRepository.findActiveUsers().map { it.toDto() }
    }
    
    private fun User.toDto() = UserDto(
        id = id!!,
        username = username,
        email = email,
        displayName = displayName,
        avatar = avatar,
        phone = phone,
        status = status,
        role = role,
        enabled = enabled,
        lastLoginAt = lastLoginAt,
        createdAt = createdAt!!
    )
}
